iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0
生成式 AI

Semantic Kernel 的魔力-用.NET探索生成式應用系列 第 25

LLM 別再亂來!收服 Prompt 和 Plugin Function

  • 分享至 

  • xImage
  •  

在開發 LLM(大型語言模型)應用的過程中,有沒有發現有時候執行的結果跟你預期的有點不一樣?你設計的 Prompt(提示語)或是 Plugin function(外卦功能)的調用,經常會跑出有點困惑的結果?這時候如果有一個有效的追蹤和管理工具,我們就能進行追蹤、記錄並改善。Semantic Kernel 框架當然也提供了這方面的機制,本篇內容就來說說如何偷偷觀察 Prompt 和 Plugin Function。

https://ithelp.ithome.com.tw/upload/images/20241008/20126569ATSjTeVo7T.png

為什麼我們需要追蹤管理 Prompt 和 Plugin function?

LLM 是個很聰明但又愛偷懶的小天才,也有點喜歡「自作主張」。就像一個廚師,你給了食材和菜單,他可能照SOP做,也可能按自己的風格來個「隨意加料」創造驚喜。對於 LLM 應用來說,Prompt 是給它的「指令」或「菜單」,而 Plugin function 則是額外的「廚具」或「配料」。當這些指令和功能互動時,可能會出現意料之外的結果。所以,追蹤管理 Prompt 和 Plugin function 調用,能幫助我們了解以下幾個問題:

  • 我的指令 LLM 有乖乖照做嗎? 追蹤 Prompt 的生成能確保 LLM 沒有「瘋言亂語」。
  • Plugin function 有發揮應有的效果嗎? 是否在正確的時間點發揮作用。
  • 為什麼結果跟想像的不一樣? 透過日誌記錄快速查出問題,找到產生奇怪結果的原因。

在追蹤管理過程中,能做些什麼?

  • 記錄與分析 Prompt 渲染的真實情況
    每次都記錄 Prompt 的完整內容,包含system prompt 、user prompt、assistant prompt,可以更好的理解與LLM互動的過程。

  • Plugin function 調用的細節掌控
    Plugin function 是讓 LLM 更聰明的秘技,但若是用得不對,可能反而會讓模型變得「瞎忙」。透過追蹤每個 Plugin function 調用的狀況,可以知道具體執行了什麼動作,甚至可以優化這些功能的使用頻率或順序,讓模型表現更穩定。

  • 優化資源使用
    調用各種 Plugin function 或是生成各式各樣的 Prompt,都是需要資源的。隨著應用規模變大,多餘、重覆或無效的調用可能會影響整個應用。透過追蹤與管理能讓我們有效控管資源,避免不必要的浪費。

IFunctionInvocationFilter 與 IPromptRenderFilter

Semantic Kernel 提供了 IFunctionInvocationFilter 與 IPromptRenderFilter 二個介面,做為 function invoke 與 Prompt Render 的過濾器,因此藉由實現這二個介面可以針對 function 以及 prompt 進行觀察進而實現記錄。讓我以Day 20 的範例來示範如何實現收服 Prompt 和 Plugin Function。

  • IFunctionInvocationFilter 實作
    以 await next(context) 做為分界,進入調用 Function 以及完成 Function 調用,因此可以透過記錄 context.Function.Name 追蹤調用順序,而 metadata 則是包含了一些細節資訊,例如OpenAI 的 SystemFingerprint、Usage(Token Cost)...等。
    註:如果 SystemFingerprint 值發生變化,則表示 OpenAI環境發生改變,將生成不同的輸出。
private sealed class MyFunctionFilter : IFunctionInvocationFilter
{
    public async Task OnFunctionInvocationAsync(FunctionInvocationContext context, Func<FunctionInvocationContext, Task> next)
    {
        Console.WriteLine($"========= MyFunctionFilter In =========");
        Console.WriteLine($"Function Invoking {context.Function.Name}\n\n");

        await next(context);

        var metadata = context.Result?.Metadata;

        if (metadata is not null)
        {
            Console.WriteLine($"========= MyFunctionFilter Out =========");
            foreach (var item in metadata)
            {
                Console.WriteLine($"{item.Key}: {JsonSerializer.Serialize(item.Value)}");
            }
        }

        Console.WriteLine($"========= MyFunctionFilter End =========\n\n");
    }
}
  • IPromptRenderFilter 實作
    同樣以await next(context) 做為分界,在 PromptRenderFilter 也能取得 Function Name資訊,而 PromptRenderContext 則是可以追蹤渲染後的 Prompt,甚至有必要時還能將Prompt置換掉。例如對 Prompt 內容進行審查,以避免洩漏機敏資訊等需求,就可以在 PromptRenderFilter 實作相關過濾邏輯。
private sealed class MyPromptFilter : IPromptRenderFilter
{
    public async Task OnPromptRenderAsync(PromptRenderContext context, Func<PromptRenderContext, Task> next)
    {
        Console.WriteLine($"========= MyPromptFilter In =========");
        Console.WriteLine($"Rendering prompt for {context.Function.Name}\n\n");

        await next(context);

        Console.WriteLine($"========= MyPromptFilter Out =========");
        Console.WriteLine($"Rendered prompt for {System.Text.RegularExpressions.Regex.Unescape(context.RenderedPrompt)}");

        Console.WriteLine($"========= MyPromptFilter End =========\n\n");
    }
}
  • kernel 物件加入Filters
kernel.PromptRenderFilters.Add(new MyPromptFilter());
kernel.FunctionInvocationFilters.Add(new MyFunctionFilter());

  • 輸出結果
========= MyFunctionFilter In =========
Function Invoking Function_6cee94ef6ead45c8a1b4463f9aee659c


========= MyPromptFilter In =========
Rendering prompt for Function_6cee94ef6ead45c8a1b4463f9aee659c


========= MyPromptFilter Out =========
Rendered prompt for Determine if the copy has been approved.  If so, respond with a single word: 'yes'

History:
[
  {
    "Role": "Assistant",
    "Name": "ReviewerAgent",
    "Content": "這段文案已經相對符合標準,特別是在吸引力和主題上。然而,為了進一步提升,還是可以考慮以下幾點:

1. **增加情感共鳴**:可以描述一下在忙碌生活中,清洗工作的繁瑣如何使人感到壓力,並強調使用AI吸塵器後帶來的輕鬆感受。

2. **豐富的視覺形容詞**:在描述產品時,加入更多的視覺形容詞,以使畫面更加生動,例如描述潔淨過後的室內環境。

3. **保持短段落結構**:確保每段落的結構保持在4到5句,以增強信息的可讀性。

4. **更頻繁的使用「你」和「我」**:試著在文中使用更多的「你」和「我」,以提升個人化的感覺。

根據這些建議進一步調整文案後,將更能吸引消費者的注意並讓其印象加深。"
  }
]
========= MyPromptFilter End =========


========= MyFunctionFilter Out =========
Id: "chatcmpl-AG5yAhVhBTd8J3jn8unJIqJlE7a1D"
CreatedAt: "2024-10-08T14:59:18+00:00"
SystemFingerprint: "fp_f85bea6784"
Usage: {"OutputTokens":1,"InputTokens":1020,"TotalTokens":1021}
FinishReason: "Stop"
ContentTokenLogProbabilities: []
========= MyFunctionFilter End =========

結語

LLM 應用開發,就像是駕馭一艘太空船。需要掌控每個指令、每個工具的使用情況,才能穩定的輸出生成結果。透過 Semantic Kernel 進行 Prompt 生成和 Plugin 調用的追蹤管理,就像是讓太空船加裝了更聰明的導航系統,避免失控以及找出最佳行車路線。所以,別再讓 LLM 自由發揮!適度進行日誌和追蹤管理吧。


上一篇
打破迷思:Semantic Kernel 飛天接地,實現地端模型連接!
下一篇
好夥伴:整合 Azure AI Inference SDK
系列文
Semantic Kernel 的魔力-用.NET探索生成式應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言